package cn.com.captureNetPacket;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.ConcurrentHashMap;

import cn.com.captureNetPacket.model.NetworkInfo;
import cn.com.captureNetPacket.model.SignallingInfo;
import cn.com.captureNetPacket.model.SignallingInfoDto;
import cn.com.captureNetPacket.util.JsonPathUtil;
import cn.com.captureNetPacket.util.RedisConfig;
import cn.com.captureNetPacket.util.Tools;
import cn.com.captureNetPacket.voice.AnalysisRTP;
import cn.com.captureNetPacket.voice.AnalysisSIP;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Data
@Slf4j
public abstract class Analysis extends Thread{
	// 保存所有的信令状态,每一个都有唯一的callid
	public static  ConcurrentHashMap<String ,SignallingInfo> callSignallingInfos=new ConcurrentHashMap<String,SignallingInfo>();
	// 根据服务器IP地址和clientIP地址保存的信令。同一个client的最后一个信令一定是最后的
	public static  ConcurrentHashMap<String ,SignallingInfo> clientSignallingCallInfos=new ConcurrentHashMap<String,SignallingInfo>();
	    protected boolean isTimeOut =false;
	    protected boolean stopThread =false;
	    protected LocalDateTime startTime= LocalDateTime.now();
	   	protected LocalDateTime lastGetPacketDateTime= LocalDateTime.now();
	    protected NetworkInfo reverseNetworkInfo, positiveNetworkInfo;
	    protected int sleepTime=CaptureNetPacketService.getAppConfig().getPacketCollectIntervalTime();
		// 剩余保留数量
//		protected   int surplus=CaptureNetPacketService.getConfig().getSurplus();
		protected   int surplus=CaptureNetPacketService.surplus;
	   	public Analysis() {
	   		
	   	};
	   	public Analysis(NetworkInfo networkInfo) {
			   log.debug("Analysis 初始化了。");
	   	  this.positiveNetworkInfo =networkInfo;
          reverseNetworkInfo=new NetworkInfo(networkInfo.getDestinationIP(), networkInfo.getSourceIP(), networkInfo.getDestinationMac(),networkInfo.getSourceMac(), networkInfo.getTransportLayer(), networkInfo.getDestinationPort(),networkInfo.getSourcePort());
	   	};
	       @Override
	   	public void run() {
	   		try {
	   			log.debug(" Analysis thread {} starting   !!! TransportLayer: {} ", positiveNetworkInfo.getNetworkInfoKey(),positiveNetworkInfo.getTransportLayer());
	   			 initAnalysis();
	   					while(!stopThread) {
	   						try {
								try {
//									log.debug("Analysis thread {} runing   !!! ",positiveNetworkInfo.getNetworkInfoKey());
									analysisPackageData();
								}catch (Exception e) {
									log.error("run analysisPackageData Exception Error {}",e);
									e.printStackTrace();
								}
							/*	if(positiveNetworkInfo.getTransportLayer().equals("SIP")) {
	   							log.debug("Analysis sip thread {} sleep   !!! {} ms",positiveNetworkInfo.getNetworkInfoKey(),sleepTime);
								}*/
	   							Thread.sleep(sleepTime);
	   						} catch (InterruptedException e) {
//									log.debug("Interrupted run{} 工作。 NetworkInfo: {}.",positiveNetworkInfo.getTransportLayer(), positiveNetworkInfo.getNetworkInfoKey(), e.getMessage());
								analysisSortPackageData();
	   						}catch (Exception e) {
	   							log.error("run Exception Error {}",e);
//	   							e.printStackTrace();
	   						}

	   					}
	   		}catch (Exception e) {
	   			log.error(" thread Exception {} Exception   !!!  ", positiveNetworkInfo.getNetworkInfoKey(),e);
	   			e.printStackTrace();
	   		}
				   try {
					   analysisPackageData();
				   }catch (Exception e) {
					   log.error("run analysisPackageData Exception Error {}",e);
				   }
			   try {
				   analysisPackageData();
			   }catch (Exception e) {
				   log.error("end run analysisPackageData Exception Error {}",e);
			   }

			   try {
				   endAnalysis();
			   }catch (Exception e) {
				   log.error("end run analysisPackageData Exception Error {}",e);
			   }finally {
				   startTime=null;
				   lastGetPacketDateTime=null;
				   positiveNetworkInfo=null;
				   reverseNetworkInfo=null;
			   }



//	   		log.debug("Analysis thread {} stoping   !!! ",firstNetworkInfo.getNetworkInfoKey());
	   		 
	   	}
	
	       
	       
	       
	   	// 初始化数据
	       public abstract void  initAnalysis();

			/**
			 *  被唤醒后，将数据包根据协议及时进行排序，避免网络抖动
			 */
			public abstract void  analysisSortPackageData();
			/**
			 * 循环处理数据，采集到一定数量的包后，进行组包。
			 */

			public abstract void  analysisPackageData();


	       //结束之前处理剩余所有数据 
	       public abstract void  handelAllPackageData();
	       public abstract void  endAnalysis();
	       
	       
	       
	       // 根据网络信息唯一标示获取信令
	       public static SignallingInfo getLastSignallingInfo(NetworkInfo networkInfo){
	    	   SignallingInfo signallingInfo=null;
	    	   String firstRedisKey=networkInfo.getSourceIP()+">"+networkInfo.getSourcePort();
	    	   String reverseRedisKey=networkInfo.getDestinationIP()+">"+networkInfo.getDestinationPort();
//	    	   log.debug("正在获取sip里的信令: firstRedisKey: {} reverseRedisKey: {} ",firstRedisKey,reverseRedisKey);
	    	   //获取所有sip信令里面的信令
	    	   signallingInfo=clientSignallingCallInfos.get(firstRedisKey);
	    	   if(signallingInfo==null)
	    	   signallingInfo=clientSignallingCallInfos.get(reverseRedisKey);
	    	   try{
	    		   String tempString=null;
	    		   if(signallingInfo==null ) {
	    			   tempString= RedisConfig.getValue(firstRedisKey);
	    			   if(tempString!=null) {
	    				   log.debug(" getLastSignallingInfo -> 通过网络信息获取redis中的信令 key {} : SignallingInfo:  {}   ",Tools.getjsonString(networkInfo),tempString);
	    			   signallingInfo=JsonPathUtil.getValue(tempString, "$", SignallingInfoDto.class).toSignallingInfo();
	    			   }
	    		   }
	    		   if(signallingInfo==null) {
	    			   tempString= RedisConfig.getValue(reverseRedisKey);
	    			   if(tempString!=null) {
	    				   log.debug("r getLastSignallingInfo -> 通过网络信息获取redis中的信令 key {} : SignallingInfo:  {}   ",Tools.getjsonString(networkInfo),tempString);
	    			    signallingInfo=JsonPathUtil.getValue(tempString, "$", SignallingInfoDto.class).toSignallingInfo();
	    			    
	    			    }
	    		   }
	    	   }catch (Exception e) {
				log.warn("getLastSignallingInfo -> 通过网络信息获取redis中的信令失败: {}  Exception ",Tools.getjsonString(networkInfo),e);
			}
	    	   
	    	   
	    	   
	    	   return signallingInfo;
	    	   
	       }
	     // 根据唯一标示获取信令
	   	public static SignallingInfo getSignallingInfo(String callid){
	   		SignallingInfo signallingInfo=null;
	   		signallingInfo=callSignallingInfos.get(callid);
			if(signallingInfo!=null)
				return signallingInfo;
			signallingInfo=callSignallingInfos.get(callid);
			return signallingInfo;
	   		 
		}
	   	
	   	
	  //提供给定时任务清理
		
		public static  void clearTask() {

			// 清理掉 signallingInfo。防止内存泄漏
			for ( String sikey: clientSignallingCallInfos.keySet()) {
				SignallingInfo si= clientSignallingCallInfos.get(sikey);
				if(si==null)continue;
				if(Tools.isHeartTimeOutPacket(si.getBeginTime())&& si.getRingTime()==null) {
					clientSignallingCallInfos.remove(sikey);
					continue;
				}
				if(si.getBeginTime().plus(3, ChronoUnit.MINUTES).isBefore(LocalDateTime.now()))
				clientSignallingCallInfos.remove(sikey);
			}
			//清理掉拨号不接通的情况
			for ( String sikey: callSignallingInfos.keySet()) {
				SignallingInfo si= callSignallingInfos.get(sikey);
				if(si==null)continue;
				if(Tools.isHeartTimeOutPacket(si.getBeginTime())&& si.getRingTime()==null) {
					 callSignallingInfos.remove(sikey);
					continue;
				}
				if(si.getBeginTime().plus(3, ChronoUnit.MINUTES).isBefore(LocalDateTime.now()))
					 callSignallingInfos.remove(sikey);
			}
			try {
			ThreadPoolTaskExecutor threadPoolTaskExecutor= (ThreadPoolTaskExecutor) CaptureNetPacketService.getTaskService();
			if(threadPoolTaskExecutor!=null) {
				log.debug("threadPoolTaskExecutor 线程池情况: {}", threadPoolTaskExecutor.getActiveCount());
			}
			}catch (Exception e){
				log.warn("打印线程池失败:  " ,e);
			}



			AnalysisRTP.garbageCollection();
			AnalysisSIP.garbageCollection();




		}
		/**
		 * 
			* <strong>Title: <strong>
			* <p>Description: 唤醒当前线程<p>
			* <p>Company: </p> 
			*<strong>Copyright:</strong> Copyright (c) 2019
			* @version: 1.0
			* @author  ASUS:augustWei
			* @date  2020 上午12:16:10
		 */
		public void awaken() {
			try {
//			log.debug("正在唤醒当前线程......");
				/*if(positiveNetworkInfo.getTransportLayer().equals("SIP")) {
					log.debug("Analysis sip thread {} awaken   !!! {} ms 强制唤醒。",positiveNetworkInfo.getNetworkInfoKey(),sleepTime);
				}*/
				this.interrupt();
			}catch (Exception e){
				log.debug("线程唤醒失败: {} ",this.positiveNetworkInfo.getNetworkInfoKey(),e);
			}
		}
		
	       
}
